#include "stdafx.h"
#include "JamesSys.h"
#include "SPUtil.h"
#include "ChartMultiData.h"
#include "Global.h"
#include "Signal.h"

auto IsOdd = [](int n) -> bool
{
	if (n % 2 == 0)
		return true;
	else
		return false;
};

CJamesSys::CJamesSys()
{
}

CJamesSys::CJamesSys(string name) 
	:CSysUnit(name)
{

}


CJamesSys::~CJamesSys()
{
}

bool CJamesSys::Run()
{
	int curIndex = m_MainData->E - 1;
	return Run(curIndex);
}

bool CJamesSys::Run(int a_Index)
{
	if (!m_MainData)
		return false;
	if (a_Index < m_MainData->S || a_Index >= m_MainData->E)
		return false;

	MarketPositionType mptType = mptNone;
	if (RealTime == true)
		mptType = GetTodayMarketPosition();
	else
		mptType = GetMarketPosition();

	if (mptType == mptNone)
		return CheckEnter(a_Index);
	else
	{
		CheckLossCut(a_Index);
		CheckProfitCut(a_Index);
	}
	
	return true;
}

bool CJamesSys::CheckEnter(int a_Index)
{
	// Check the height of day.
	//double curDayHeight = CSPUtil::GetDayHeight(a_Index);
	//if (curDayHeight > MinHeight)
	//	return false;

	//int di = CSPUtil::GetDayIndex(a_Index, m_MainData);
	//if (di <= 4)
	//	return false;
	int sigCount = GetDaySignalCount(a_Index);
	if (sigCount > 0)
		return false;


	// Check the crossed count of day
	int crossedCount = CSPUtil::GetBandCrossCount(a_Index, m_MainData);
	if (crossedCount > 0)
		return false;

	BandType btType = CSPUtil::WhichBandIsNear(m_MainData, a_Index);
	if (btType == btNone)
		return false;
	int bandEvenCount = 0;
	CSignal* newSig = NULL;
	if (btType == btUpper) // Prepare for a sell signal
	{
		bandEvenCount = CSPUtil::GetUpperEvenCount(a_Index);
		if (bandEvenCount < 3)
			return false;
		int di = CSPUtil::GetDayIndex(a_Index - bandEvenCount, m_MainData);
		if (di == 0)
			return false;

		// Check if the point is the highest point of the day.
		bool nearDayHigh = CSPUtil::IncludedDayHigh(a_Index, bandEvenCount + 1, m_MainData);
		if (nearDayHigh == false)
			return false;
		int underLowCount = CSPUtil::UnderLowCountInUpperBand(a_Index, bandEvenCount, m_MainData);
		if (underLowCount < 1)
			return false;
		bool enterRange = CSPUtil::IsInFarRangeUnderTop(a_Index, 0.2, m_MainData);
		if (enterRange == false)
			return false;

		double dayHigh = CSPUtil::GetDayHigh(a_Index);
		if (dayHigh < 0.0)
			return false;
		double entryPoint = dayHigh - 0.2;
		// Trigger a Signal of Sell.
		newSig = AddSignal(a_Index, stSell, entryPoint);

		if (RealTime == true && newSig)
			PutEntryOrder(newSig);
	}
	else if (btType == btLower) // Prepare for a buy signal
	{
		bandEvenCount = CSPUtil::GetLowerEvenCount(a_Index);
		if (bandEvenCount < 3)
			return false;
		int di = CSPUtil::GetDayIndex(a_Index - bandEvenCount, m_MainData);
		if (di == 0)
			return false;
		// Check if the point is the lowest point of the day.
		bool nearDayLow = CSPUtil::IncludedDayLow(a_Index, bandEvenCount + 1, m_MainData);
		if (nearDayLow == false)
			return false;
		int overHighCount = CSPUtil::OverHighCountInLowerBand(a_Index, bandEvenCount, m_MainData);
		if (overHighCount < 1)
			return false;
		bool enterRange = CSPUtil::IsInFarRangeOverBottom(a_Index, 0.2, m_MainData);
		if (enterRange == false)
			return false;

		double dayLow = CSPUtil::GetDayLow(a_Index);
		if (dayLow < 0.0)
			return false;
		double entryPoint = dayLow + 0.2;
		// Trigger a Signal of Buy.
		newSig = AddSignal(a_Index, stBuy, entryPoint);

		if (RealTime == true && newSig)
			PutEntryOrder(newSig);
	}

	return true;
}

const double gap = 0.3;

bool CJamesSys::CheckLossCut(int a_Index)
{
	CSignal* newSig = NULL;
	CSignal* lastSig = m_SigList.back();
	if (lastSig->Type == stBuy)
	{
		if (m_MainData->Low[a_Index] <= lastSig->Price - gap)
		{
			newSig = AddSignal(a_Index, stExitBuy, lastSig->Price - gap);
			if (RealTime == true && newSig)
				PutLossCutOrder(newSig);
		}
	}
	else if (lastSig->Type == stSell)
	{
		if (m_MainData->High[a_Index] >= lastSig->Price + gap)
		{
			newSig = AddSignal(a_Index, stExitSell, lastSig->Price + gap);
			if (RealTime == true && newSig)
				PutLossCutOrder(newSig);
		}
	}
	return true;
}

bool CJamesSys::CheckProfitCut(int a_Index)
{
	int crossedCount = CSPUtil::GetBandCrossCount(a_Index, m_MainData);
	if (crossedCount <= 0)
		return false;

	CSignal* lastSig = m_SigList.back();
	double min = 0.0, max = 0.0, avg = 0.0;
	CSPUtil::GetMinMaxAvg(min, max, avg);
	CSignal* newSig = NULL;
	if (lastSig->Type == stBuy)
	{
		bool reachedLimit = CSPUtil::IsReachedUpperLimitLow(a_Index, m_MainData);
		if (reachedLimit == false)
			return false;

		int bandEvenCount = CSPUtil::GetUpperEvenCount(a_Index);
		if (bandEvenCount < 3)
			return false;

		newSig = AddSignal(a_Index, stExitBuy, m_MainData->Close[a_Index]);
		if (RealTime == true && newSig)
			PutProfitCutOrder(newSig);
	}
	else if (lastSig->Type == stSell)
	{
		bool reachedLimit = CSPUtil::IsReachedBottomLimitHigh(a_Index, m_MainData);
		if (reachedLimit == false)
			return false;

		int bandEvenCount = CSPUtil::GetLowerEvenCount(a_Index);
		if (bandEvenCount < 3)
			return false;

		newSig = AddSignal(a_Index, stExitSell, m_MainData->Close[a_Index]);
		if (RealTime == true && newSig)
			PutProfitCutOrder(newSig);
	}
	return true;
}
